import Guide from '~/components/layout/guide'
import Snippet from '~/components/snippet'
import { InlineCode } from '~/components/text/code'
import { Image } from '~/components/media'
import Caption from '~/components/text/caption'
import Note from '~/components/text/note'
import Link from '~/components/text/link'
import DeploySection from '~/components/guides/deploy-section'

export const meta = {
  title: 'Create and Deploy a MongoDB-Powered Node.js API with ZEIT Now',
  description:
    'Create a serverless Node.js API with data powered by MongoDB then deploy it as a serverless app with ZEIT Now.',
  published: '2019-05-24T17:53:20.489Z',
  authors: ['timothy'],
  url: '/guides/deploying-a-mongodb-powered-api-with-node-and-now',
  image: `${
    process.env.ASSETS
  }/guides/deploying-a-mongodb-powered-api-with-node-and-now/card.png`,
  name: 'MongoDB',
  type: 'API',
  editUrl: 'pages/guides/deploying-a-mongodb-powered-api-with-node-and-now.mdx',
  lastEdited: '2020-02-19T19:12:27.000Z'
}

In this guide, we will walk you through creating and [deploying](/docs/v2/deployments/basics/) a [Node.js](https://nodejs.org/) API powered by [MongoDB](https://www.mongodb.com/), on [ZEIT Now](/).

<Image
  src={`${
    process.env.ASSETS
  }/guides/deploying-a-mongodb-powered-api-with-node-and-now/card.png`}
  width={2048 / 2.75}
  height={1170 / 2.75}
  oversize
/>

## Step 1: Preparing Your Project

To start this example, you will need to have [setup a MongoDB Atlas account and database](https://docs.atlas.mongodb.com/getting-started/).

Make sure that the cluster has [whitelisted connections](https://docs.atlas.mongodb.com/getting-started/#whitelist-your-connection-ip-address) from anywhere, since ZEIT Now does not support static IP addresses.

Get started by creating a project directory and `cd` into it:

<Snippet dark text="mkdir my-mongodb-api && cd my-mongodb-api" />
<Caption>
  Creating and entering into the <InlineCode>my-mongodb-api</InlineCode>{' '}directory.
</Caption>

Next, [initialize](https://docs.npmjs.com/cli/init) the project:

<Snippet dark text="npm init" />
<Caption>
  Initializing the project, this creates a <InlineCode>package.json</InlineCode>{' '}file.
</Caption>

<Note>
  During the initializing process, npm will ask questions about your project.
  Answer these how you wish; there are no prerequisites for this example.
</Note>

Next, install [the MongoDB Node.js client](https://mongodb.github.io/node-mongodb-native/), which you will use to connect to your MongoDB cluster and database:

<Snippet dark text="npm i mongodb" />
<Caption>
  Adding the <InlineCode>mongodb</InlineCode> Node.js client as a <Link href="https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file">dependency</Link> to the project.
</Caption>

To connect to MongoDB, you will need your MongoDB connection string.

You can get the connection string by clicking "Connect" on the Cluster Overview page within the MongoDB Atlas dashboard, then choosing "Connect your Application":

<Image
  src={`${
    process.env.ASSETS
  }/guides/deploying-a-mongodb-powered-api-with-node-and-now/connect.png`}
  width={2382/2.5}
  height={1624/2.5}
  oversize
/>
<Caption>Getting the connection string from the MongoDB Atlas connection modal.</Caption>

To use your MongoDB connection string without hard-coding it in your project, you can add your connection string to the project as a [Now Secret](/docs/v2/deployments/environment-variables-and-secrets#securing-environment-variables-using-secrets) using the [Now CLI](/download#now-cli) to keep them secure:

<Snippet dark text="now secrets add my-mongodb-uri mongodb+srv://<user>:<password>@my-cluster-uf345.mongodb.net/<database-name>?retryWrites=true" />
<Caption>
  Adding a <Link href="/v2/deployments/environment-variables-and-secrets#securing-environment-variables-using-secrets">secret</Link>, using the MongoDB connection string, to the project.
</Caption>

<Note>
  Make sure to use your own connection string and add your password to the
  string.
</Note>

Finally, set up [the `now.json` configuration file](/docs/configuration) that instructs ZEIT Now to make available the [Secret](/docs/v2/deployments/environment-variables-and-secrets#securing-environment-variables-using-secrets) you defined:

```json
{
  "name": "my-mongodb-api",
  "version": 2,
  "env": {
    "MONGODB_URI": "@my-mongodb-uri"
  }
}
```

<Caption>
  A{' '}
  <Link href="/docs/configuration">
    <InlineCode>now.json</InlineCode> configuration file
  </Link>{' '}
  for development and deployment.
</Caption>

The above file tells ZEIT Now the following:

- The name of the project is "my-mongodb-api"
- An [Environment Variable](/docs/v2/deployments/environment-variables-and-secrets/), `env`, should be accessible in the app with the value of the secret you added in the first step

<Note>
  To use this environment variable in local development, you will need to use a{' '}
  <InlineCode>.env</InlineCode> file.{' '}
  <Link href="/docs/v2/development/environment-variables/">
    Read more about local development and environment variables
  </Link>
  .
</Note>

## Step 2: Creating the API

Now that you have a MongoDB database, it's time to create the Node.js API endpoint that will be fetching data from it.

<Note>
  If you don't have any data to insert into your database, you can{' '}
  <Link href="https://docs.atlas.mongodb.com/getting-started/#insert-data-into-your-cluster">
    load a sample dataset
  </Link>{' '}
  to start.
</Note>

For this example, create a file called `users.js` in a new directory called `api`.

The `users.js` file will act as the endpoint for getting information from your database. The file should contain the following contents:

```js
// Import Dependencies
const url = require('url')
const MongoClient = require('mongodb').MongoClient

// Create cached connection variable
let cachedDb = null

// A function for connecting to MongoDB,
// taking a single parameter of the connection string
async function connectToDatabase(uri) {
  // If the database connection is cached,
  // use it instead of creating a new connection
  if (cachedDb) {
    return cachedDb
  }

  // If no connection is cached, create a new one
  const client = await MongoClient.connect(uri, { useNewUrlParser: true })

  // Select the database through the connection,
  // using the database path of the connection string
  const db = await client.db(url.parse(uri).pathname.substr(1))

  // Cache the database connection and return the connection
  cachedDb = db
  return db
}

// The main, exported, function of the endpoint,
// dealing with the request and subsequent response
module.exports = async (req, res) => {
  // Get a database connection, cached or otherwise,
  // using the connection string environment variable as the argument
  const db = await connectToDatabase(process.env.MONGODB_URI)

  // Select the "users" collection from the database
  const collection = await db.collection('users')

  // Select the users collection from the database
  const users = await collection.find({}).toArray()

  // Respond with a JSON string of all users in the collection
  res.status(200).json({ users })
}
```

<Caption>
  A Node.js API Endpoint that retrieves data from a MongoDB database collection.
</Caption>

<Note>
  In the code snippet above, you probably noticed that we used{' '}
  <InlineCode>res.status()</InlineCode> and <InlineCode>res.json()</InlineCode>{' '}
  to send a response. These methods are automatically added for you when you use
  <InlineCode>@now/node</InlineCode>. Read more about this in the <Link href="/docs/v2/deployments/official-runtimes/node-js-now-node#helpers">
    <InlineCode>@now/node</InlineCode> Runtime documentation page
  </Link>.
</Note>

## Step 3: Local Development

Now that you have your MongoDB database, an API endpoint, and configuration all done, you can start to [develop your API, and apps, locally](/docs/v2/development/basics).

Using Now CLI, you can start a development process from your terminal that mimics your production environment using the configuration you provided in your `now.json` file.

To start developing, create a `.env` file containing the `MONGODB_URI` environment variable and the connection string you want to use locally:

```bash
MONGODB_URI=mongodb+srv://<user>:<password>@my-cluster-uf345.mongodb.net/<database-name>?retryWrites=true
```

<Caption>
  A <InlineCode>.env</InlineCode> file containing the{' '}
  <InlineCode>MONGODB_URI</InlineCode> environment variable and its value for
  local development.
</Caption>

This file allows the ZEIT Now development process to use the environment variable with a value, since you are using a Now Secret in production which isn't accessible outside of the secure deployment environment.

Next, run the Now CLI development command from the terminal:

<Snippet dark text="now dev" />
<Caption>Starting Now CLI's dev process from the terminal.</Caption>

After starting the development process, Now CLI will provide you with a localhost address for where your app is running. This is commonly <http://localhost:3000> unless the port is taken.

Using the default port, you can find your new API endpoint at <http://localhost:3000/api/users.js>.

## Step 4: Deploying

<DeploySection meta={meta} />

You can view the deployment from this guide, using the API path, here: <https://my-mongodb-api.now.sh/api/users.js>

export default ({ children }) => <Guide meta={meta}>{children}</Guide>

export const config = {
  amp: 'hybrid'
}
